package com.wish.handjdkProxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * @Author: suliucheng
 * @Date: 2021/2/28 21:15
 * @Description:
 */
public class GPProxy {
    private static String ln = "\r\n";

    public static Object newProxyInstance(GPClassLoader loader, Class<?>[] interfaces, GPInvocationHandler h)
            throws IllegalArgumentException {
        try {
//        1.生成源代码
            String proxySrc = generateSrc(interfaces[0]);

//        2.将生成的源代码输出到磁盘，保存.java文件
            String path = GPProxy.class.getResource("").getPath();
            File f = new File(path + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();

//        3.编译源代码，并且生成.class文件
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);
            CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();

//        4.将class文件中的内容，动态加载到JVM中
            Class<?> proxyClass = loader.findClass("$Proxy0");
            Constructor<?> constructor = proxyClass.getConstructor(GPInvocationHandler.class);
            f.delete(); //删除生成的Java文件

//        5.返回被代理后的代理对象
            return constructor.newInstance(h);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成代码
     * @param interfaces
     * @return
     */
    private static String generateSrc(Class<?> interfaces) {

        StringBuffer src = new StringBuffer();
        src.append("package com.wish.handjdkProxy;" + ln);
        src.append("import java.lang.reflect.Method;" + ln);
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
        src.append("GPInvocationHandler h;" + ln);
        src.append("public $Proxy0(GPInvocationHandler h){" + ln);
        src.append("this.h = h;" + ln);
        src.append("}" + ln);

        for (Method m : interfaces.getMethods()) {
            src.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
            src.append("try {" + ln);
            src.append("Method m = " + interfaces.getName() + ".class.getMethod(\"" + m.getName() +"\",new Class[]{});" + ln);
            src.append("this.h.invoke(this,m,null);" + ln);
            src.append("} catch(Throwable e){e.printStackTrace();}" + ln);
            src.append("}" + ln);
        }


        src.append("}");
        return src.toString();
    };
}
